Over time, newer client device types and classes of devices (e.g., smartphones, tablets, personal computers and so forth) are introduced into the marketplace, each of which has different capabilities relative to other device types and classes. As a result, various versions of software code evolve, including the APIs and other mechanisms that such clients use to exchange data with a data service. Similarly, software versions change for other reasons, such as when new data properties are introduced, or when others become obsolete or irrelevant.
Some of the changes may be “breaking” changes, in that older version client software fails once a newer version is in use at the data service. For example, a set of data sent to a client may have a new data property, which version 3.0 client software expects, but which causes version 2.0 or below clients to fail. Similarly, a data property that is no longer needed may be removed from a newer version. Such version changes can break the client software code in that a client may get some unexpected data that the client software is not configured to handle, or be missing a piece of data that client software is expecting.
A typical way to ensure that the correct version of software is used with a given client is to maintain and run different sets of the various software versions at the data service, and individually match each client device to the appropriate one of the sets, e.g., via a load balancer or the like that routes different clients to different, version-appropriate servers. As there can be many different types of client devices and software versions, managing the relatively large number of such versions becomes very complex. An alternative solution is to maintain multiple code paths within code for each software version (e.g., “if version 2.0 then do X, if version 3.0 then do Y, if version 4.0 then do Z”). This solution tends to become unmaintainable after even a small number of version-based alternate code paths.